use crate::app::event::Event;
use crate::app::state::{Consumed, SessionHelper};
use crate::app::{AeonError, DynError};
use crate::sketchbook::data_structs::{
ChangeArgEssentialData, ChangeArgMonotoneData, ModelData, UninterpretedFnData,
};
use crate::sketchbook::event_utils::{make_reversible, mk_model_event, mk_model_state_change};
use crate::sketchbook::ids::UninterpretedFnId;
use crate::sketchbook::model::{ModelState, UninterpretedFn};
use crate::sketchbook::JsonSerde;
const ADD_FN_PATH: &str = "add";
const ADD_DEFAULT_FN_PATH: &str = "add_default";
const REMOVE_FN_PATH: &str = "remove";
const SET_DATA_PATH: &str = "set_data";
const SET_ID_PATH: &str = "set_id";
const SET_ARITY_PATH: &str = "set_arity";
const INCREMENT_ARITY_PATH: &str = "increment_arity";
const DECREMENT_ARITY_PATH: &str = "decrement_arity";
const SET_EXPRESSION_PATH: &str = "set_expression";
const SET_MONOTONICITY_PATH: &str = "set_monotonicity";
const SET_ESSENTIALITY_PATH: &str = "set_essentiality";
impl ModelState {
pub(super) fn perform_uninterpreted_fn_event(
&mut self,
event: &Event,
at_path: &[&str],
) -> Result<Consumed, DynError> {
let component_name = "model/uninterpreted_fn";
if Self::starts_with(ADD_DEFAULT_FN_PATH, at_path).is_some() {
Self::assert_path_length(at_path, 1, component_name)?;
self.event_add_default_uninterpreted_fn(event)
} else if Self::starts_with(ADD_FN_PATH, at_path).is_some() {
Self::assert_path_length(at_path, 1, component_name)?;
self.event_add_uninterpreted_fn(event)
} else {
Self::assert_path_length(at_path, 2, component_name)?;
let fn_id_str = at_path.first().unwrap();
let fn_id = self.get_uninterpreted_fn_id(fn_id_str)?;
self.event_modify_uninterpreted_fn(event, &at_path[1..], fn_id)
}
}
pub(super) fn event_add_uninterpreted_fn(
&mut self,
event: &Event,
) -> Result<Consumed, DynError> {
let component_name = "model/uninterpreted_fn";
let payload = Self::clone_payload_str(event, component_name)?;
let fn_data = UninterpretedFnData::from_json_str(payload.as_str())?;
let arity = fn_data.arguments.len();
self.add_empty_uninterpreted_fn_by_str(&fn_data.id, &fn_data.name, arity)?;
self.set_fn_annot_by_str(&fn_data.id, &fn_data.annotation)?;
let reverse_at_path = ["uninterpreted_fn", &fn_data.id, "remove"];
let reverse_event = mk_model_event(&reverse_at_path, None);
Ok(make_reversible(event.clone(), event, reverse_event))
}
pub(super) fn event_add_default_uninterpreted_fn(
&mut self,
event: &Event,
) -> Result<Consumed, DynError> {
let component_name = "model/uninterpreted_fn";
Self::assert_payload_empty(event, component_name)?;
let arity = 0;
let fn_id = self.generate_uninterpreted_fn_id("fn", Some(1));
let uninterpreted_fn = UninterpretedFn::new_without_constraints(fn_id.as_str(), arity)?;
let fn_data = UninterpretedFnData::from_fn(&fn_id, &uninterpreted_fn);
self.add_empty_uninterpreted_fn_by_str(&fn_data.id, &fn_data.name, arity)?;
let state_change = mk_model_state_change(&["uninterpreted_fn", "add"], &fn_data);
let reverse_at_path = ["uninterpreted_fn", &fn_data.id, "remove"];
let reverse_event = mk_model_event(&reverse_at_path, None);
Ok(make_reversible(state_change, event, reverse_event))
}
pub(super) fn event_modify_uninterpreted_fn(
&mut self,
event: &Event,
at_path: &[&str],
fn_id: UninterpretedFnId,
) -> Result<Consumed, DynError> {
let component_name = "model/uninterpreted_fn";
if Self::starts_with(REMOVE_FN_PATH, at_path).is_some() {
if event.payload.is_some() {
let message = "Payload must be empty for uninterpreted fn removing.".to_string();
return AeonError::throw(message);
}
let fn_data = UninterpretedFnData::from_fn(&fn_id, self.get_uninterpreted_fn(&fn_id)?);
self.remove_uninterpreted_fn(&fn_id)?;
let state_change = mk_model_state_change(&["uninterpreted_fn", "remove"], &fn_data);
let reverse_at_path = ["uninterpreted_fn", "add"];
let payload = fn_data.to_json_str();
let reverse_event = mk_model_event(&reverse_at_path, Some(&payload));
Ok(make_reversible(state_change, event, reverse_event))
} else if Self::starts_with(SET_DATA_PATH, at_path).is_some() {
let payload = Self::clone_payload_str(event, component_name)?;
let new_data = UninterpretedFnData::from_json_str(&payload)?;
let new_fn = new_data.to_uninterpreted_fn(self)?;
let original_fn = self.get_uninterpreted_fn(&fn_id)?;
let original_data = UninterpretedFnData::from_fn(&fn_id, original_fn);
if &new_fn == original_fn {
return Ok(Consumed::NoChange);
}
self.set_raw_function(&fn_id, new_fn)?;
let new_fn = self.get_uninterpreted_fn(&fn_id)?;
let new_data = UninterpretedFnData::from_fn(&fn_id, new_fn);
let state_change = mk_model_state_change(&["uninterpreted_fn", "set_data"], &new_data);
let mut reverse_event = event.clone();
reverse_event.payload = Some(original_data.to_json_str());
Ok(make_reversible(state_change, event, reverse_event))
} else if Self::starts_with(SET_ID_PATH, at_path).is_some() {
let new_id = Self::clone_payload_str(event, component_name)?;
if fn_id.as_str() == new_id.as_str() {
return Ok(Consumed::NoChange);
}
self.set_uninterpreted_fn_id_by_str(fn_id.as_str(), new_id.as_str())?;
let model_data = ModelData::from_model(self);
let state_change = mk_model_state_change(&["uninterpreted_fn", "set_id"], &model_data);
let reverse_at_path = ["uninterpreted_fn", new_id.as_str(), "set_id"];
let reverse_event = mk_model_event(&reverse_at_path, Some(fn_id.as_str()));
Ok(make_reversible(state_change, event, reverse_event))
} else if Self::starts_with(SET_ARITY_PATH, at_path).is_some() {
let new_arity: usize = Self::clone_payload_str(event, component_name)?.parse()?;
let original_arity = self.get_uninterpreted_fn(&fn_id)?.get_arity();
if new_arity == original_arity {
return Ok(Consumed::NoChange);
}
self.set_uninterpreted_fn_arity(&fn_id, new_arity)?;
let fn_data = UninterpretedFnData::from_fn(&fn_id, self.get_uninterpreted_fn(&fn_id)?);
let state_change = mk_model_state_change(&["uninterpreted_fn", "set_arity"], &fn_data);
let mut reverse_event = event.clone();
reverse_event.payload = Some(original_arity.to_string());
Ok(make_reversible(state_change, event, reverse_event))
} else if Self::starts_with(INCREMENT_ARITY_PATH, at_path).is_some() {
Self::assert_payload_empty(event, component_name)?;
self.increment_fn_arity(&fn_id)?;
let fn_data = UninterpretedFnData::from_fn(&fn_id, self.get_uninterpreted_fn(&fn_id)?);
let state_change =
mk_model_state_change(&["uninterpreted_fn", "increment_arity"], &fn_data);
let reverse_at_path = ["uninterpreted_fn", fn_id.as_str(), "decrement_arity"];
let reverse_event = mk_model_event(&reverse_at_path, None);
Ok(make_reversible(state_change, event, reverse_event))
} else if Self::starts_with(DECREMENT_ARITY_PATH, at_path).is_some() {
Self::assert_payload_empty(event, component_name)?;
self.decrement_fn_arity(&fn_id)?;
let fn_data = UninterpretedFnData::from_fn(&fn_id, self.get_uninterpreted_fn(&fn_id)?);
let state_change =
mk_model_state_change(&["uninterpreted_fn", "decrement_arity"], &fn_data);
let reverse_at_path = ["uninterpreted_fn", fn_id.as_str(), "increment_arity"];
let reverse_event = mk_model_event(&reverse_at_path, None);
Ok(make_reversible(state_change, event, reverse_event))
} else if Self::starts_with(SET_EXPRESSION_PATH, at_path).is_some() {
let new_expression = Self::clone_payload_str(event, component_name)?;
let original_expression = self
.get_uninterpreted_fn(&fn_id)?
.get_fn_expression()
.to_string();
if new_expression == original_expression {
return Ok(Consumed::NoChange);
}
self.set_uninterpreted_fn_expression(&fn_id, new_expression.as_str())?;
let new_fn = self.get_uninterpreted_fn(&fn_id)?;
let fn_data = UninterpretedFnData::from_fn(&fn_id, new_fn);
if fn_data.expression == original_expression {
return Ok(Consumed::NoChange);
}
let state_change =
mk_model_state_change(&["uninterpreted_fn", "set_expression"], &fn_data);
let mut reverse_event = event.clone();
reverse_event.payload = Some(original_expression);
Ok(make_reversible(state_change, event, reverse_event))
} else if Self::starts_with(SET_MONOTONICITY_PATH, at_path).is_some() {
let payload = Self::clone_payload_str(event, component_name)?;
let change_data = ChangeArgMonotoneData::from_json_str(payload.as_str())?;
let original_monotonicity = *self
.get_uninterpreted_fn(&fn_id)?
.get_monotonic(change_data.idx);
if original_monotonicity == change_data.monotonicity {
return Ok(Consumed::NoChange);
}
self.set_uninterpreted_fn_monotonicity(
&fn_id,
change_data.monotonicity,
change_data.idx,
)?;
let fn_data = UninterpretedFnData::from_fn(&fn_id, self.get_uninterpreted_fn(&fn_id)?);
let state_change =
mk_model_state_change(&["uninterpreted_fn", "set_monotonicity"], &fn_data);
let mut reverse_event = event.clone();
let reverse_change = ChangeArgMonotoneData::new(change_data.idx, original_monotonicity);
reverse_event.payload = Some(reverse_change.to_json_str());
Ok(make_reversible(state_change, event, reverse_event))
} else if Self::starts_with(SET_ESSENTIALITY_PATH, at_path).is_some() {
let payload = Self::clone_payload_str(event, component_name)?;
let change_data = ChangeArgEssentialData::from_json_str(payload.as_str())?;
let original_essentiality = *self
.get_uninterpreted_fn(&fn_id)?
.get_essential(change_data.idx);
if original_essentiality == change_data.essentiality {
return Ok(Consumed::NoChange);
}
self.set_uninterpreted_fn_essentiality(
&fn_id,
change_data.essentiality,
change_data.idx,
)?;
let fn_data = UninterpretedFnData::from_fn(&fn_id, self.get_uninterpreted_fn(&fn_id)?);
let state_change =
mk_model_state_change(&["uninterpreted_fn", "set_essentiality"], &fn_data);
let mut reverse_event = event.clone();
let reverse_change =
ChangeArgEssentialData::new(change_data.idx, original_essentiality);
reverse_event.payload = Some(reverse_change.to_json_str());
Ok(make_reversible(state_change, event, reverse_event))
} else {
Self::invalid_path_error_specific(at_path, component_name)
}
}
}